
/***************************************************************************
 *   jell - library                                                        *
 *                                                                         *
 *   Copyright (C) 2008 by kuerant                                         *
 *                         <kuerant@gmail.com>                             *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This library is distributed in the hope that it will be usefull, but  *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
 *   Library General Public License for more details.                      *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston,                *
 *   MA 02111-1307, USA                                                    *
 ***************************************************************************/

#ifndef JEFI_JELL_BUF_HPP
#define JEFI_JELL_BUF_HPP

#include "jell/buf.hpp"

namespace   jell
{
    class   JellBuf :   public  Buf
    {
    public  :
        JellBuf(const size_t capacity, void* ptr)
            : m_capacity(capacity), m_ptr(ptr), m_size(0)
        {
            rewindRead();
            rewindWrite();
        }
        virtual ~JellBuf() {}

    public  :
        virtual const size_t    size    (void) const { return m_size; }
        virtual const char*     data    (void) { return static_cast< char* >(data_ptr()); }

        virtual const size_t    capacity(void) const { return m_capacity; }
        virtual const void*     ptr     (void) { return m_ptr; }

        virtual void clear(void) throw(JellException)
        {
            m_size = 0;

            rewindRead();
            rewindWrite();
        }
        virtual void assign(const char* data, size_t size) throw(JellException)
        {
            if (size > m_capacity) {
                // overflow
                throw JellException(String::format("buffer overflow (capacity=%d data-size=%d)", m_capacity, size),
                                    ERROR::OVERFLOW,
                                    __LINE__, __FILE__, __FUNC__);
            }

            void*   _ptr = data_ptr();
            memmove(_ptr, data, size);
            m_size = size;

            // adjust write ptr
            this->rewindWrite();
            this->adjustWritePtr(size);
        }

        virtual void append(const char* data, size_t size) throw(JellException)
        {
            if ((m_size + size) > m_capacity) {
                // overflow
                throw JellException(String::format("buffer overflow (capacity=%d data-size=%d)", m_capacity, (m_size + size)),
                                    ERROR::OVERFLOW,
                                    __LINE__, __FILE__, __FUNC__);
            }

            void*   _ptr = data_ptr();
            char*   _p = static_cast< char* >(_ptr);
            memmove(_p + m_size, data, size);
            m_size += size;

            // adjust write ptr
            this->adjustWritePtr(size);
        }

    public  :
        virtual void    size(size_t actual_size)
        {
            if (actual_size > 0) {
                m_size = actual_size;
            }
        }

        virtual void    rewindRead(void)
        {
            m_readOffset = 0;
            m_readPtr = data_ptr();
        }

        virtual void*   getReadPtr(void)                       { return m_readPtr; }
        virtual size_t  getSizeToRead(void) const              { return m_size - m_readOffset; }
        virtual void*   adjustReadPtr(const offset_type offset)
        {
            m_readOffset += offset;
            char*   _p = static_cast< char * >(data_ptr());
            _p += m_readOffset;
            m_readPtr = _p;

            return  m_readPtr;
        }

        virtual void    rewindWrite(void)
        {
            m_writeOffset = 0;
            m_writePtr = data_ptr();
        }

        virtual void*   getWritePtr(void)
        {
            return m_writePtr;
        }
        virtual size_t  getSizeToWrite(void) const
        {
            if (m_size > 0) {
                return m_size - m_writeOffset;
            }
            else {
                return m_capacity - m_writeOffset;
            }
        }
        virtual void*   adjustWritePtr(const offset_type offset)
        {
            m_writeOffset += offset;
            char*   _p = static_cast< char * >(data_ptr());
            _p += m_writeOffset;
            m_writePtr = _p;

            return  m_writePtr;
        }

    private :
        void*   data_ptr(void)    { return m_ptr; }

    private :
        size_t  m_capacity;
        void*   m_ptr;
        size_t  m_size;

        size_t  m_readOffset;
        void*   m_readPtr;
        size_t  m_writeOffset;
        void*   m_writePtr;
    };  // class JellBuf

}   // namespace jell

#endif  // JEFI_JELL_BUF_HPP

